<template>
  <div class="pdf-viewer">
    <!-- 工具栏 -->
    <div class="pdf-toolbar">
      <div class="toolbar-left">
        <el-button size="small" :disabled="currentPage <= 1" @click="prevPage">上一页</el-button>
        <span class="page-info">{{ currentPage }} / {{ totalPages }}</span>
        <el-button size="small" :disabled="currentPage >= totalPages" @click="nextPage">下一页</el-button>
        <span v-if="isDownloading" class="download-status"> (下载中: {{ Math.round(loadingProgress) }}%) </span>
      </div>
      <div class="toolbar-right">
        <el-button size="small" @click="zoomOut">放大</el-button>
        <span class="zoom-info">{{ Math.round(scale * 100) }}%</span>
        <el-button size="small" @click="zoomIn">缩小</el-button>
        <el-button size="small" :disabled="!downloadedData" @click="downloadPdf">下载</el-button>
      </div>
    </div>
    <!-- PDF 内容区域 -->
    <div v-loading="loading" class="pdf-container">
      <!-- 加载进度 -->
      <div v-if="loading" class="loading-info">
        <el-progress :percentage="loadingProgress" />
        <p>正在下载 PDF... {{ Math.round(loadingProgress) }}%</p>
      </div>
      <!-- 错误状态 -->
      <div v-else-if="totalPages === 0 && !loading" class="error-info">
        <el-icon class="error-icon" size="48" color="#f56c6c">
          <WarningFilled />
        </el-icon>
        <p>PDF加载失败</p>
        <el-button size="small" @click="loadPdf">重新加载</el-button>
      </div>
      <!-- PDF 页面容器 - 改为单页显示 -->
      <div v-else class="pdf-pages">
        <div class="pdf-page">
          <canvas :id="`pdf-page-${currentPage}`" class="page-canvas"></canvas>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { ref, onMounted, onUnmounted, nextTick } from 'vue'
  import { ElMessage } from 'element-plus'
  import { WarningFilled } from '@element-plus/icons-vue'
  import * as PDFJS from 'pdfjs-dist'

  // 设置 worker 的路径和中文字符映射支持
  PDFJS.GlobalWorkerOptions.workerSrc = window.location.origin + '/static/pdf.worker.min.mjs'
  defineOptions({ name: 'PdfViewer' })
  interface Props {
    pdfUrl: string // PDF 下载预签名 URL
    headUrl?: string // PDF HEAD请求预签名 URL
    chunkSize?: number // 分片大小
  }
  const props = withDefaults(defineProps<Props>(), {
    chunkSize: 1024 * 1024, // 1MB 分片
  })
  // 响应式数据
  const loading = ref(false)
  const loadingProgress = ref(0)
  let pdfDoc: any = null // 不要用 ref 包裹 PDF.js 对象
  const totalPages = ref(0) // 总页数
  const currentPage = ref(1) // 当前页码
  const scale = ref(1.0)
  let downloadedData: Uint8Array | null = null // 不要用 ref 包裹
  const availablePages = ref(0) // 当前可用页数
  const isDownloading = ref(false) // 是否正在下载

  onMounted(() => {
    loadPdf()
  })
  // 获取文件大小
  const getFileSize = async (): Promise<number> => {
    // 如果有专门的HEAD URL，优先使用
    if (props.headUrl) {
      try {
        const headResponse = await fetch(props.headUrl, {
          method: 'HEAD',
        })
        if (headResponse.ok) {
          const contentLength = headResponse.headers.get('content-length')
          if (contentLength) {
            const fileSize = parseInt(contentLength)
            return fileSize
          }
        }
      } catch (error) {
        console.log('HEAD请求失败:', error)
      }
    }
    // 如果没有HEAD URL或HEAD请求失败，尝试Range请求
    if (!props.pdfUrl) {
      throw new Error('没有提供PDF URL')
    }
    try {
      const response = await fetch(props.pdfUrl, {
        method: 'GET',
        headers: {
          Range: 'bytes=0-0', // 只请求第一个字节
        },
      })
      if (response.status === 206) {
        // Partial Content - 查找Content-Range头
        const contentRange = response.headers.get('content-range')
        if (contentRange) {
          const match = contentRange.match(/bytes \d+-\d+\/(\d+)/)
          if (match) {
            const fileSize = parseInt(match[1])
            return fileSize
          }
        }
      }
    } catch (error) {
      console.log('Range请求失败:', error)
    }
    return 0
  }
  // 下载分片
  const downloadChunk = async (url: string, start: number, end: number): Promise<ArrayBuffer> => {
    const response = await fetch(url, {
      method: 'GET',
      headers: {
        Range: `bytes=${start}-${end}`,
      },
    })
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`)
    }
    return response.arrayBuffer()
  }
  // PDF解析函数
  const tryLoadPdf = async (data: Uint8Array): Promise<number> => {
    try {
      if (data.length < 1024) {
        return 0
      }
      const loadingTask = PDFJS.getDocument({
        data: data,
        disableAutoFetch: true,
        stopAtErrors: false,
        disableRange: true,
        disableStream: true,
        // 添加中文字符映射支持
        cMapUrl: '/static/cmaps/',
        cMapPacked: true,
        // 添加标准字体支持
        standardFontDataUrl: '/static/standard_fonts/',
        // 禁用字体加载以减少警告
        disableFontFace: false,
        // 更好的错误处理
        verbosity: 0, // 减少控制台输出
      })
      const doc = (await loadingTask.promise) as any
      const pages = doc.numPages
      if (pages <= 0) {
        return 0
      }
      // 如果成功加载，更新当前的PDF文档
      if (pdfDoc) {
        pdfDoc.destroy()
      }
      pdfDoc = doc
      return pages
    } catch (error: any) {
      console.log('PDF解析失败:', error.message || error.toString())
      return 0
    }
  }
  // 分片下载PDF文件
  const downloadPdfInChunks = async (url: string): Promise<Uint8Array> => {
    const fileSize = await getFileSize()
    // 如果无法获取文件大小，直接下载整个文件
    if (fileSize === 0) {
      const response = await fetch(url, {
        method: 'GET',
      })
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`)
      }
      loadingProgress.value = 100
      const data = new Uint8Array(await response.arrayBuffer())
      downloadedData = data
      // 尝试加载PDF
      const pages = await tryLoadPdf(data)
      if (pages > 0) {
        totalPages.value = pages
        availablePages.value = pages
        // 设置loading为false，让DOM先更新
        loading.value = false
        isDownloading.value = false
        // 等待DOM更新后再渲染第一页
        await nextTick()
        await new Promise((resolve) => setTimeout(resolve, 200))
        await renderPage(1)
      } else {
        throw new Error('PDF文件格式错误，无法解析')
      }
      return data
    }
    // 小文件直接下载
    if (fileSize <= props.chunkSize) {
      const response = await fetch(url, {
        method: 'GET',
      })
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`)
      }
      loadingProgress.value = 100
      const data = new Uint8Array(await response.arrayBuffer())
      downloadedData = data
      // 尝试加载PDF
      const pages = await tryLoadPdf(data)
      if (pages > 0) {
        totalPages.value = pages
        availablePages.value = pages
        // 设置loading为false，让DOM先更新
        loading.value = false
        isDownloading.value = false
        // 等待DOM更新后再渲染第一页
        await nextTick()
        await new Promise((resolve) => setTimeout(resolve, 200))
        await renderPage(1)
      } else {
        throw new Error('PDF文件格式错误，无法解析')
      }
      return data
    }

    // 大文件分片下载
    const totalChunks = Math.ceil(fileSize / props.chunkSize)
    const mergedBuffer = new Uint8Array(fileSize)
    let downloadedChunks = 0
    // 并发下载分片
    const maxConcurrency = 3
    for (let i = 0; i < totalChunks; i += maxConcurrency) {
      const batch = []
      for (let j = 0; j < maxConcurrency && i + j < totalChunks; j++) {
        const chunkIndex = i + j
        const start = chunkIndex * props.chunkSize
        const end = Math.min(start + props.chunkSize - 1, fileSize - 1)
        const promise = downloadChunk(url, start, end).then(async (arrayBuffer) => {
          const chunk = new Uint8Array(arrayBuffer)
          mergedBuffer.set(chunk, start)
          downloadedChunks++
          loadingProgress.value = Math.floor((downloadedChunks / totalChunks) * 100)
        })
        batch.push(promise)
      }
      await Promise.all(batch)
    }
    downloadedData = mergedBuffer
    isDownloading.value = false
    // 尝试加载完整PDF
    const pages = await tryLoadPdf(mergedBuffer)
    if (pages > 0) {
      totalPages.value = pages
      availablePages.value = pages
      if (loading.value) {
        loading.value = false
        // 等待DOM更新后再渲染第一页
        await nextTick()
        await new Promise((resolve) => setTimeout(resolve, 200))
        await renderPage(1)
      }
    } else {
      throw new Error('PDF文件格式错误，无法解析')
    }
    return mergedBuffer
  }

  // 加载PDF文档
  const loadPdf = async () => {
    loading.value = true
    loadingProgress.value = 0
    isDownloading.value = true
    availablePages.value = 0

    try {
      if (!props.pdfUrl) throw new Error('没有提供PDF URL')
      await downloadPdfInChunks(props.pdfUrl)
    } catch (error: any) {
      // 根据错误类型显示不同的错误信息
      if (error.message.includes('403')) {
        ElMessage.error('PDF访问权限不足，或签名信息过期!')
      } else if (error.message.includes('404')) {
        ElMessage.error('PDF文件不存在')
      } else if (error.message.includes('网络')) {
        ElMessage.error('网络连接失败，请检查网络')
      } else if (error.message.includes('格式错误')) {
        ElMessage.error('PDF文件格式错误，无法解析')
      } else {
        ElMessage.error(`PDF加载失败: ${error.message || '未知错误'}`)
      }

      // 重置状态
      loading.value = false
      isDownloading.value = false
      loadingProgress.value = 0
      totalPages.value = 0
      availablePages.value = 0
    }
  }

  // 渲染单页
  const renderPage = async (pageNumber: number) => {
    if (!pdfDoc) {
      console.log('PDF文档未加载')
      return
    }

    try {
      const page = await pdfDoc.getPage(pageNumber)
      const canvas = document.getElementById(`pdf-page-${pageNumber}`) as HTMLCanvasElement

      if (!canvas) {
        console.log(`Canvas元素未找到: pdf-page-${pageNumber}`)
        // 等待一下再试
        await new Promise((resolve) => setTimeout(resolve, 50))
        const retryCanvas = document.getElementById(`pdf-page-${pageNumber}`) as HTMLCanvasElement
        if (!retryCanvas) {
          console.error(`Canvas元素仍未找到: pdf-page-${pageNumber}`)
          return
        }

        const viewport = page.getViewport({ scale: scale.value })
        retryCanvas.width = viewport.width
        retryCanvas.height = viewport.height
        const context = retryCanvas.getContext('2d')!
        await page.render({ canvasContext: context, viewport }).promise
        console.log(`页面 ${pageNumber} 渲染完成(重试)`)
        return
      }

      const viewport = page.getViewport({ scale: scale.value })
      canvas.width = viewport.width
      canvas.height = viewport.height
      const context = canvas.getContext('2d')!
      await page.render({ canvasContext: context, viewport }).promise
    } catch (error) {
      console.error(`页面 ${pageNumber} 渲染失败:`, error)
    }
  }

  // 页面导航
  const prevPage = async () => {
    if (currentPage.value > 1) {
      currentPage.value--
      await renderPage(currentPage.value)
    }
  }

  const nextPage = async () => {
    if (currentPage.value < totalPages.value) {
      currentPage.value++
      await renderPage(currentPage.value)
    }
  }

  // 缩放控制
  const zoomOut = async () => {
    if (scale.value < 2) {
      scale.value += 0.2
      await reRenderCurrentPage()
    }
  }

  const zoomIn = async () => {
    if (scale.value > 0.5) {
      scale.value -= 0.2
      await reRenderCurrentPage()
    }
  }

  // 重新渲染当前页面
  const reRenderCurrentPage = async () => {
    await renderPage(currentPage.value)
  }

  // 下载PDF
  const downloadPdf = () => {
    if (downloadedData) {
      const blob = new Blob([new Uint8Array(downloadedData)], { type: 'application/pdf' })
      const url = URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url
      a.download = 'document.pdf'
      a.click()
      URL.revokeObjectURL(url)
      ElMessage.success('文件下载完成')
    } else {
      ElMessage.warning('文件尚未下载完成')
    }
  }

  onUnmounted(() => {
    if (pdfDoc) {
      pdfDoc.destroy()
    }
    downloadedData = null
  })
</script>

<style scoped lang="scss">
  .pdf-viewer {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: #f5f5f5;
  }

  .pdf-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 20px;
    background: white;
    border-bottom: 1px solid #e0e0e0;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

    .toolbar-left,
    .toolbar-right {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .page-info,
    .zoom-info {
      font-size: 14px;
      color: #666;
      min-width: 80px;
      text-align: center;
    }

    .download-status {
      font-size: 12px;
      color: #1890ff;
      margin-left: 10px;
    }
  }

  .pdf-container {
    flex: 1;
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }

  .loading-info {
    padding: 40px;
    text-align: center;

    p {
      margin-top: 15px;
      color: #666;
    }
  }

  .error-info {
    padding: 40px;
    text-align: center;

    .error-icon {
      margin-bottom: 16px;
    }

    p {
      margin: 16px 0;
      color: #f56c6c;
      font-size: 16px;
    }
  }

  .pdf-pages {
    flex: 1;
    overflow: hidden;
    padding: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .pdf-page {
    display: flex;
    justify-content: center;

    .page-canvas {
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      background: white;
      border: 1px solid #ddd;
    }
  }
</style>
